﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Projeto
{
    // Classe que gerencia as cenas do jogo
    public class GerenciadorTelas
    {
        private Jogo jogo; // Armazena uma refêrencia do jogo
        private EstadoJogo telaAtual; // Cena atual e próxima cena do jogo
        private EstadoJogo proximaTela; // Armazena todas as cenas
        private Dictionary<EstadoJogo, Tela> telas; // Dicionário de cenas
        private bool transition; // Verifica se tem transição para acontecer
        private float alpha = 1.0f; // Alpha da cena
        private Texture2D imagemTela; // Imagem para fazer a transição
        protected SpriteBatch spriteBatch; // Referência para o sprite batch do jogo

        // Construtor do gerenciador de cenas
        public GerenciadorTelas(Jogo jogo)
        {
            // Armazena a referencia do jogo que o chamou
            this.jogo = jogo;

            // Recebe o sprite batch do jogo via serviços do XNA
            this.spriteBatch = (SpriteBatch)jogo.Services.GetService(typeof(SpriteBatch));

            // Carrega a textura que vai servir para fazer o efeito de transição
            imagemTela = jogo.Content.Load<Texture2D>("Cartas/carta_mendigo");

            // Define a cena atual como vazia
            this.telaAtual = EstadoJogo.None;

            // Define a próxima cena como vazia
            this.proximaTela = EstadoJogo.None;

            // Define a transição como verdadeira
            this.transition = false;

            // Inicializa o dicionário de cenas
            this.telas = new Dictionary<EstadoJogo, Tela>();

            // Troca a cena vazia pela cena de introdução
            MudaTela(EstadoJogo.Intro);
        }

        // Atualiza a cena
        public void Update(GameTime tempoJogo)
        {
            // Caso não tenha transição 
            if (!transition)
            {
                // Atualiza a cena atual
                telas[telaAtual].Update(tempoJogo);
            }
            else
            {
                // Se tem transição e a cena atual é diferente de vazia
                if (telaAtual != EstadoJogo.None)
                {
                    // Aumenta o alpha conforme o tempo, ou seja,
                    // aumenta o preto na tela (fade-out)
                    // a imagem começa a desaparecer
                    alpha += (float)tempoJogo.ElapsedGameTime.TotalMilliseconds * 0.001f;
                    if (alpha >= 1.0f)
                    {
                        // Mantem o alpha entre 0 e 1
                        MathHelper.Clamp(alpha, 0, 1);
                        // Remove a cena anterior (atual até o momento)
                        telas.Remove(telaAtual);
                        // Cena atual recebe estado vazio
                        telaAtual = EstadoJogo.None;
                    }
                }
                else
                {
                    if (alpha > 0.0f)
                    {
                        /* Diminui o alpha conforme o tempo, ou seja,
                           diminui o preto na tela (fade-in)
                           a imagem começa a aparecer */
                        alpha -= (float)tempoJogo.ElapsedGameTime.TotalMilliseconds * 0.001f;
                    }
                    else
                    {
                        // Mantém o alpha entre 0 e 1
                        MathHelper.Clamp(alpha, 0, 1);
                        // Cena atual recebe o próximo estado
                        telaAtual = proximaTela;
                        // Acaba a transição
                        transition = false;
                    }
                }
            }
        }

        // Desenha a cena
        public void Draw(GameTime tempoJogo)
        {
            /* Se cena atual for diferente de vazio
               desenha a cena atual
               senão desenha a próxima cena */
            if (telaAtual != EstadoJogo.None)
                telas[telaAtual].Draw(tempoJogo);
            else
                telas[proximaTela].Draw(tempoJogo);

            // Se existir transição, aplica o efeito de fade-in e fade-out
            if (transition)
                FadeBackBufferToBlack();
        }

        // Troca as cenas do jogo
        public void MudaTela(EstadoJogo proximaTela)
        {
            this.proximaTela = proximaTela; // Guarda a próxima cena
            this.transition = true; // Define que agora existe uma transição de cenas
            switch (proximaTela) // Caso a cena seja alguma especificada realiza a inserção da mesma no dicionário
            {
                case EstadoJogo.Intro:
                    telas.Add(EstadoJogo.Intro, new TelaIntro(jogo));// Adiciona a cena de introdução ao dicionário
                    
                    break;

                case EstadoJogo.EscolhaModo:
                    telas.Add(EstadoJogo.EscolhaModo, new TelaEscolhaModoDeJogo(jogo));
                    break;
              
                case EstadoJogo.GameEncontre:
                    telas.Add(EstadoJogo.GameEncontre, new TelaJogoModoEncontre(jogo));// Adiciona a cena de jogo ao dicionário 
                    break;

                case EstadoJogo.Creditos:
                    telas.Add(EstadoJogo.Creditos, new TelaCredito(jogo));// Adiciona a cena de créditos ao dicionário 
                    break;

                case EstadoJogo.GameReflexo:
                    telas.Add(EstadoJogo.GameReflexo, new TelaJogoModoReflexo(jogo));// Adiciona a cena de jogo ao dicionário 
                    break;

               
            }
        }

        /*  Desenha um sprite translúcido preto, usado para telas de fading in e out,
           e para escurecer o fundo. */

        private void FadeBackBufferToBlack()
        {
            // Cria uma nova janela de visualização, conforme a janela atual do jogo
            Viewport viewport = jogo.GraphicsDevice.Viewport;

            // Desenha uma imagem preta com o alpha definido
            spriteBatch.Draw(imagemTela,
                             new Rectangle(0, 0, viewport.Width, viewport.Height),
                             new Color(0, 0, 0, alpha));
        }
    }
}
